﻿using System;
using System.Windows.Forms;

namespace Schedulr.Tools
{
    /// <summary>
    /// A scope for a UI action during which a specified control is disabled and applied a certain cursor.
    /// </summary>
    public class UIActionScope : IDisposable
    {
        #region Fields

        /// <summary>
        /// The previous cursor of the associated control.
        /// </summary>
        private readonly Cursor oldCursor;

        /// <summary>
        /// The previous state of the associated control.
        /// </summary>
        private readonly bool oldEnabled;

        /// <summary>
        /// The control on which to display the status description.
        /// </summary>
        private readonly ToolStripItem statusControl;

        /// <summary>
        /// The previous status description on the status control.
        /// </summary>
        private readonly string oldDescription;

        #endregion

        #region Properties

        /// <summary>
        /// The control to disable and for which to set the cursor.
        /// </summary>
        private readonly Control controlToDisable;

        /// <summary>
        /// Gets the control to disable and for which to set the cursor.
        /// </summary>
        public Control ControlToDisable
        {
            get { return this.controlToDisable; }
        }

        /// <summary>
        /// The status control to use if no specific one is given in the constructor.
        /// </summary>
        private static ToolStripItem globalStatusControl;

        /// <summary>
        /// Gets or sets the status control to use if no specific one is given in the constructor.
        /// </summary>
        public static ToolStripItem GlobalStatusControl
        {
            get
            {
                return UIActionScope.globalStatusControl;
            }
            set
            {
                UIActionScope.globalStatusControl = value;
            }
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="UIActionScope"/> class.
        /// </summary>
        /// <remarks>The <see cref="Control"/> will be set to the currently active form for this application.</remarks>
        public UIActionScope()
            : this(Form.ActiveForm, Cursors.WaitCursor, null, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UIActionScope"/> class.
        /// </summary>
        /// <param name="control">The control to disable and for which to set the cursor.</param>
        public UIActionScope(Control control)
            : this(control, Cursors.WaitCursor, null, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UIActionScope"/> class.
        /// </summary>
        /// <param name="control">The control to disable and for which to set the cursor.</param>
        /// <param name="newCursor">The new cursor to set.</param>
        public UIActionScope(Control control, Cursor newCursor)
            : this(control, newCursor, null, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UIActionScope"/> class.
        /// </summary>
        /// <param name="actionDescription">The description for the current action.</param>
        public UIActionScope(string actionDescription)
            : this(Form.ActiveForm, Cursors.WaitCursor, actionDescription, null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UIActionScope"/> class.
        /// </summary>
        /// <param name="actionDescription">The description for the current action.</param>
        /// <param name="statusControl">The control on which to display the action description.</param>
        public UIActionScope(string actionDescription, ToolStripItem statusControl)
            : this(Form.ActiveForm, Cursors.WaitCursor, actionDescription, statusControl)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UIActionScope"/> class.
        /// </summary>
        /// <param name="controlToDisable">The control to disable and for which to set the cursor.</param>
        /// <param name="newCursor">The new cursor to set.</param>
        /// <param name="actionDescription">The description for the current action.</param>
        /// <param name="statusControl">The control on which to display the action description.</param>
        public UIActionScope(Control controlToDisable, Cursor newCursor, string actionDescription, ToolStripItem statusControl)
        {
            this.controlToDisable = controlToDisable;
            this.statusControl = statusControl;
            if (this.statusControl == null)
            {
                this.statusControl = UIActionScope.GlobalStatusControl;
            }

            if (this.statusControl != null)
            {
                this.oldDescription = this.statusControl.Text;
                this.statusControl.Text = actionDescription;
                if (this.statusControl.Owner != null)
                {
                    this.statusControl.Owner.Refresh();
                }
            }

            if (newCursor != null)
            {
                if (this.controlToDisable != null)
                {
                    this.oldCursor = controlToDisable.Cursor;
                    this.controlToDisable.Cursor = newCursor;
                }
                else
                {
                    this.oldCursor = Cursor.Current;
                    Cursor.Current = newCursor;
                }
            }

            if (this.controlToDisable != null)
            {
                this.oldEnabled = this.controlToDisable.Enabled;
                this.controlToDisable.Enabled = false;
            }

            Application.DoEvents();
        }

        #endregion

        #region Dispose

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Releases unmanaged and, optionally, managed resources.
        /// </summary>
        /// <param name="disposing"><see langword="true"/> to release both managed and unmanaged resources; <see langword="false"/> to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (this.controlToDisable != null)
                {
                    this.controlToDisable.Enabled = this.oldEnabled;
                }

                if (this.oldCursor != null)
                {
                    if (this.controlToDisable != null)
                    {
                        this.controlToDisable.Cursor = this.oldCursor;
                    }
                    else
                    {
                        Cursor.Current = this.oldCursor;
                    }
                }

                if (this.statusControl != null)
                {
                    this.statusControl.Text = this.oldDescription;
                    if (this.statusControl.Owner != null)
                    {
                        this.statusControl.Owner.Refresh();
                    }
                }
            }
        }

        #endregion
    }
}